# -*- coding: utf-8 -*-
from typing import Iterable
"""
属性相关的魔术方法
"""


class A:

    def __init__(self):
        self.name = "a"
        self.counter = 0

    def __getattr__(self, item):
        """
        只有当读取对象不存在的属性时，该方法会被调用
        :param item:
        :return:
        """
        print("getting {}".format(item))
        # raise AttributeError
        return None

    def __getattribute__(self, item):
        """
        只要读取对象的属性，都会调用该方法, 在此方法中，使用对象的属性，有可能产生递归
        :param item:
        :return:
        """
        print('__getattribute__ {!r}'.format(item))
        if item == 'name':
            self.counter += 1
        return super().__getattribute__(item)  # 或者 object.__getattribute__(self,item)

    def __setattr__(self, key, value):
        print('__setattr__ {!r} {!r}'.format(key, value))
        super().__setattr__(key, value)  # 或者 object.__setattr__(self,key,value)

    def __delattr__(self, item):
        print('__delattr__ {!r}'.format(item))
        super().__delattr__(item)  # 或者 object.__delattr__(self,item)
        
    def __dir__(self) -> Iterable[str]:
        lst = super().__dir__()
        return [el for el in lst if not el.startswith("_")]


class B:
    _attr = {}

    def __init__(self):
        self.name = "b"
        self.counter = 0

    def __setattr__(self, key, value):
        self._attr[key] = value

    def __getattr__(self, item):
        if item not in self._attr:
            raise AttributeError
        return self._attr[item] # 所有实例共享同名属性值

    def __delitem__(self, key):
        del self._attr[key]


if __name__ == '__main__':
    a = A()
    print(a.name)
    print(a.age)
    print(a.counter)
    a.tel = '136'
    a.age = 22

    print('dir', dir(a))


    b1 = B()
    b2 = B()
    b1.data = 'b1_data'
    b2.data = 'b2_data'

    print(b1.data, b2.data)


